package ricky.loader
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.utils.ByteArray;
	import flash.utils.Dictionary;
	import flash.utils.describeType;
	
	import ricky.Interface.IDecoder;
	import ricky.Interface.ILoadComplete;
	import ricky.Interface.ILoader;
	import ricky.events.MulipleLoaderEvent;
	import ricky.loader.protocol.Decoder;
	import ricky.plutonium.Application;

	[Event(name="call_Functions", type="ricky.events.MulipleLoaderEvent")]
	
	[Event(name="all_Complete", type="ricky.events.MulipleLoaderEvent")]

	/**
	 * 多文件加载
	 * @author：蒲
	 * @data:2011.5.12
	 */
	public class MultipleLoader extends EventDispatcher implements ILoadComplete
	{
		public function MultipleLoader(target:IEventDispatcher=null)
		{
			super(target);
			load=new Dictionary();
			queue=new QueueWait();
			callBackList=new Dictionary();
			deCoderDict=new Dictionary();
			loadClass=new Dictionary();
			Decoder.registerDecoder(this);
			this.addEventListener(MulipleLoaderEvent.CALL_FUNCTIONS,oncall);
		}

		/**
		 * 加载进度
		 */
		public function get onProgress():Function
		{
			return _onProgress;
		}

		/**
		 * @private
		 */
		public function set onProgress(value:Function):void
		{
			_onProgress = value;
		}

		/**
		 * 将多个资源加载到本地，不放入资源缓存。</br>
		 * 参数:</br>
		 * <b>req:Array</b> 请求的队列Request类型  </br>
		 * <b>onComplete:Function(e:Multiple):void</b> 全部加载完成时回调函数  </br>
		 * <b>onProgress：Function(e:ProgressEvent):void</b> 加载进度调用函数  </br>
		 */
		public function loadReq(req:Array,onComplete:Function,onProgress:Function):void
		{
			this.onProgress=onProgress;
			this.allCompelte=onComplete;
			
			var reqi:Request;
			var key:String
			for(var i:uint=0;i<req.length;i++)
			{
				reqi=req[i];
				addReqToQueue(reqi);
			}
		}
		
		public function appendLoad(req:Array):void
		{
			var reqi:Request;
			var key:String
			for(var i:uint=0;i<req.length;i++)
			{
				reqi=req[i];
				addReqToQueue(reqi);
			}
		}

		/**
		 * 卸载加载的请求
		 */
		public function unload(req:Request):void
		{
			this.queue.isRuning=false
			var r1:Request;
			for(var i:int;i<this.queue.size();i++)
			{
				r1=this.queue.first();
				if(r1)
				{
					if(r1.url==req.url)
						queue.setValue(i,null);
				}
			}
			
			if(this.load[req.key])
			{
				var myl:MyUrlLoader=this.load[req.key];
				callfunction(req);
				myl.close();
			}
			this.queue.isRuning=true;
			beginQueue();
		}
		
		/**
		 * 将请求加入队列
		 * @param reqi:Request 某一项请求
		 */
		public function addReqToQueue(reqi:Request):void
		{
			var key:String=reqi.key;
						
			if(callBackList[key])//如果有回调列表不为空
				(callBackList[key] as Array).push(reqi);//加入回调用列表
			else
			{
				callBackList[key]=new Array();
				(callBackList[key] as Array).push(reqi);//加入回调列表
				this.queue.add(reqi);
			}
			beginQueue();

		}
		
		/**
		 * 开始队列加载
		 */
		private function beginQueue():void
		{
			if(queue.isRuning==false)
				return;
			
			var r1:Request;
			while(this.currentLoading<this.maxLoading && queue.size()>0)
			{
				r1=this.queue.first();
				if(r1)
					loadRequest(r1);
			}
		}
		
		/**
		 * 开始加载
		 */
		protected function loadRequest(req:Request):void
		{
			req.times++;//加载次数
			currentLoading++;
			
			var key:String=req.key;
			
			load[key]=this.getLoaderClass(req);
			var loader:ILoader=load[key];
			loader.addEventListener(Event.COMPLETE,onCompelete);
			loader.addEventListener(IOErrorEvent.IO_ERROR,ioError);
			loader.addEventListener(ProgressEvent.PROGRESS,progress);
			loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
			loader.loadComplete=this;	
			loader.req=req;	
			loader.beginLoad();
		
		}
		
		/**
		 * 加载完成
		 */
		private function onCompelete(e:Event):void
		{
			var req:Request=e.currentTarget.req;
			var key:String=req.key;
			req.data=e.currentTarget.getData;

			if(req.data is ByteArray) //如果是二进制数据
				decoder(req,this);
			else
				doComplete(req);
		}
		
		/**
		 * 解码
		 */
		private function decoder(req:Request,onComplete:ILoadComplete):void
		{
			if(Application.native)
			{
				try{
					if(onByteArrayLoaded!=null)
						onByteArrayLoaded.call(null,req);
				}catch(e:Error)
				{
					trace("Error ：#MultipleLoader.decoder,line 208  ",e,req.url);
				}
			}
			
			var type:String=req.type;
			var decoder:IDecoder=deCoderDict[type];
			if(decoder)
				decoder.doDecoder(req,onComplete);
			else
				doComplete(req);
		}
		
		/**
		 * 添加解码接口
		 */
		public function addProtool(type:String,decoder:IDecoder):void
		{
			if(deCoderDict[type])
				trace("Warnings：#MultipleLoader.addProtool line,225 ",type+'exist');//
			
			this.deCoderDict[type]=decoder;
		}
		
		/**
		 * 添加下载器
		 */
		public function addLoader(suffix:String,Iloader:Class):void
		{
			if(this.loadClass[suffix])
				trace("Warnings：#MultipleLoader.addProtool 236 ",suffix+'exist');//
			
			this.loadClass[suffix]=Iloader;
		}
		
		
		/**
		 * 处理回调
		 * @param req:Request 当前请求
		 */
		public function doComplete(req:Request):void
		{
			//放入缓存
			if(req.cache!=null)
				req.cache[req.key]=req.data;
			
			//回调
			if(callBackList[req.key])
			{
				var arr:Array=callBackList[req.key] as Array;
				if(arr)
				{
					var eve:MulipleLoaderEvent=new MulipleLoaderEvent(MulipleLoaderEvent.CALL_FUNCTIONS);
					eve.reqs=arr;
					eve.data=req.data;
					this.dispatchEvent(eve);
				}
			}
			
			callfunction(req);
		}
		
		
		private function getLoaderClass(req:Request):ILoader
		{
			var suffix:String=req.type.toLocaleLowerCase();

			var clas:Class=this.loadClass[suffix];
			if(clas)
			{
				var disc:XML=describeType(clas);

				var constructor:XMLList=disc.factory.constructor.parameter;
				var par:Array=[];
				for each(var i:XML in constructor)
				{
					if(i.@optional=="false")
					{
						var t:String=i.@type;
						if(t=="*")
						{
							par.push(req.url);
						}
						else if(t=="String")
						{
							par.push(req.url);
						}
					}
				}
				
				if(par.length==0)
					return new clas();
				else if(par.length==1)
					return new clas(par[0]);
				else if(par.length==2)
					return new clas(par[0],par[1]);
				else
					return new MyUrlLoader();
			}
			else
			{
				return new MyUrlLoader();
			}
		}
		
		/**
		 * 加载数量-1，开始新队列，删除加载器，判断是否全部加载完成
		 */
		private function callfunction(req:Request):void
		{
			currentLoading--;
			
			removeLoader(req.key);
			
			beginQueue();
			
			if(currentLoading<=0)
			{
				if(allCompelte!=null)
				{
					allCompelte.call(null,this);
//					allCompelte=null;
				}
			}
		}
		
		/**
		 * 安全错误
		 */
		private function securityErrorHandler(e:SecurityErrorEvent):void
		{
			trace("SecurityErrorEvent:#MultipleLoader line 338",e.text);
			retry(e);
		}
		
		/**
		 * 读取错误
		 */
		private function ioError(e:IOErrorEvent):void
		{
			trace("IOErrorEvent:#MultipleLoader line 347",e.text);
			retry(e);
		}
		
		private function retry(e:Event):void
		{
			currentLoading--;

			var my:MyUrlLoader=e.target as MyUrlLoader;
			if(my)
			{
				var req:Request=my.req;
				if(req.times<=this.retryTimes)
				{
					if(Application.native) //如果是本地应用程序
					{
						req.url=Application.internetDomain+req.relative;
					}
					this.queue.add(req);
					beginQueue();
				}else
				{
					if(req.onEnd!=null)
						req.onEnd(req);
					if(currentLoading<=0)
					{
						if(allCompelte!=null)
							allCompelte.call(null,this);
					}
				}
			}

		}
		
		private function progress(e:ProgressEvent):void
		{
			if(onProgress!=null)
				onProgress(e);
		}
		
		/**
		 * 删除加载器
		 */
		private function removeLoader(key:String):void
		{
			var my:ILoader=this.load[key];
			if(my)
			{
				my.removeEventListener(Event.COMPLETE,this.onCompelete);
				my.removeEventListener(IOErrorEvent.IO_ERROR,this.ioError);
				if(onProgress!=null)
					my.removeEventListener(IOErrorEvent.IO_ERROR,this.onProgress);
				my=null;
				load[key]=null;
			}
			delete load[key];
			delete callBackList[key];
		}
		
		/**
		 * 循环执行回调
		 */
		private function oncall(e:MulipleLoaderEvent):void
		{
			var arr:Array=e.reqs;
			for each(var r:Request in arr)
			{
				r.data=e.data;
				if(r.onComplete!=null)
					r.onComplete.call(r,r);
			}
		}
		
		private var _allCompelte:Function;
		
		private var _onProgress:Function;

		/**
		 * 全部加载完成 function(this);
		 */
		public function get allCompelte():Function
		{
			return _allCompelte;
		}

		/**
		 * @private
		 */
		public function set allCompelte(value:Function):void
		{
			_allCompelte = value;
		}

		/**
		 * 加载器
		 */
		private var load:Dictionary;
		
		/**
		 * 解压字典
		 * deCoderDict[type]=IDecoder
		 */
		private var deCoderDict:Dictionary;//解压字典
		
		/**
		 * 下载字典
		 * loadClass[type]=ILoader
		 */
		private var loadClass:Dictionary;//下载器字典
		/**
		 * 回调用列表
		 */
		public var callBackList:Dictionary;//回调列表
		
		/**
		 * 
		 * 当二进制流加载到本地的时候调用</br>
		 * 只有 Application.native=true时候才有效
		 * @param onByteArrayLoaded(req:Request):void
		 */
		public var onByteArrayLoaded:Function;
		
		/**
		 * 等待加载队列列表
		 */
		public var queue:QueueWait; 
		
		/**
		 * 当前正在加载数
		 */
		public var currentLoading:int=0;
		
		/**
		 * 最大同时加载数
		 */		
		public var maxLoading:int=2;
		
		/**
		 * 最大重试次数
		 */
		public var retryTimes:int=3;
		
		private var _architecture:String="";
		
		private static var _instance:MultipleLoader;
		
		/**
		 * 全局加载器
		 */
		public static function get instance():MultipleLoader
		{
			if(!_instance)
				_instance=new MultipleLoader();
			return _instance;
		}

		/**
		 * 此对象的 url 属性使用 app-storage URL 架构 url 字符串以"app-storage:"开头 。此外，如果创建一个相对于 File.applicationStoreDirectory 目录的 File 对象（通过使用 resolvePath() 方法），则该 File 对象的 url 也使用 app-storage URL 架构（如示例中所示）。<br />
		 * file URL 架构）。这意味着指定的 url 字符串以是以 "file:" 开头）<br />
		 *  简单点说就是绝对路径
		 */
		public function get architecture():String
		{
			return _architecture;
		}

		/**
		 * @private
		 */
		public function set architecture(value:String):void
		{
			_architecture = value;
		}


	}
}